/**************************************************
File: $/Graphics/Graphics.js
Dependency: $/Three/*.js
**************************************************/

/* function : initVars
 * usage    : initVars();
 * --------------------
 * init the variables
 *///{{{
var initVars = function () {
    dae_cnt = dae_loaded = 0;
    stats = camera = scene = renderer = null;
    cameras = [];
    cam_rel_vecs = [];

    for (var i=0; i<10; ++i){
        objs[i] = [];
    }

    robots = objs[ObjType.ROBOT];
    kittys = objs[ObjType.KITTY];
    stones = objs[ObjType.STONE];
    monsters = objs[ObjType.MONSTER];
    balls = objs[ObjType.BALL];
    doors = objs[ObjType.DOOR];
    keys = objs[ObjType.KEY];
    skills = objs[ObjType.SKILL];

    rob_ori_rot = [];
    rob_ori_pos = [];

    robot = kitty = stone = monster = ball = door = key = skill = null;
};
//}}}

/* function : addCameras
 * usage    : addCameras();
 * --------------------
 * add cameras to the scene
 *///{{{
var addCameras = function () {
    for (var i=0; i<player_num; ++i){
        camera = new THREE.PerspectiveCamera(45, 1, 1, 200);
        camera.position.set(1,1,1);
        camera.up.set(0, 0, 1);
        camera.setViewOffset(10,10,0,0,20,20);
        cameras.push(camera);
        cam_rel_vecs.push((new THREE.Vector3(0,0,-0.1)).addSelf(ROBOT_FORE).setLength(10).negate());
        scene.add(cameras[i]);
    }
};
//}}}

/* function : addLights
 * usage    : addLights();
 * --------------------
 * add lights to the scene
 *///{{{
var addLights = function () {
	var directionalLight = new THREE.DirectionalLight(0xeeeeee );
    directionalLight.position.set(10, 10, 10);
	directionalLight.position.normalize();
	scene.add(directionalLight);
    var d_light = new THREE.DirectionalLight(0xffffff);
    d_light.position.set(-1, -1, -1);
    scene.add(d_light);
};
///}}}

/* function : createStatusBar
 * usage    : status = createStatusBar();
 * --------------------
 * return status_bar to html
 *///{{{
var createStatusBar = function () {
    var status = $("<div></div>")[0];
    var table = $("<table></table>")[0];
    status.appendChild(table);
    $("<table class='status_bar' border='0' cellspacing='10px'>\
        <tr>\
            <th colSpan=4>Player 1</th>"
        + (player_num > 1 ? "\
            <th colSpan=1>\
                <div style='width:170px'></div>\
            </th>\
            <th colSpan=4>Player 2</th>" : "")
        +"</tr>\
        <tr>\
            <td><div class='status_bar p1 skill0'>Jump</div></td>\
            <td><div class='status_bar p1 skill1'>Gun</div></td>\
            <td><div class='status_bar p1 skill2'>Dbl Jmp</div></td>\
            <td><div class='status_bar p1 skill3'>Speed Up</div></td>"
        + (player_num > 1 ? "\
            <td></td>\
            <td><div class='status_bar p2 skill0'>Jump</div></td>\
            <td><div class='status_bar p2 skill1'>Gun</div></td>\
            <td><div class='status_bar p2 skill2'>Dbl Jmp</div></td>\
            <td><div class='status_bar p2 skill3'>Speed Up</div></td>\
            " : "")
        + "</tr>\
        <tr>\
            <td><div class='status_bar p1 key0'>Red</div></td>\
            <td><div class='status_bar p1 key1'>Green</div></td>\
            <td><div class='status_bar p1 key2'>Blue</div></td>\
            <td><div class='status_bar p1 key3'>Yellow</div></td>"
        + (player_num > 1 ? "\
            <td></td>\
            <td><div class='status_bar p2 key0'>Red</div></td>\
            <td><div class='status_bar p2 key1'>Green</div></td>\
            <td><div class='status_bar p2 key2'>Blue</div></td>\
            <td><div class='status_bar p2 key3'>Yellow</div></td>\
            " : "")
        + "</tr>\
        <tr>\
            <th colSpan=4 class='status_bar p1 msg'>Game starting...</th>"
        + (player_num > 1 ? "\
            <th></th>\
            <th colSpan=4 class='status_bar p2 msg'>Game starting...</th>" : "")
        + "</tr>\
        </table>").appendTo(table);
    return status;
};
//}}}

/* function : initGraphics
 * usage    : initGraphics();
 * --------------------
 * init the graphics.
 *///{{{
//}}}

/* function : initGraphics
 * usage    : initGraphics();
 * --------------------
 * init the graphics.
 *///{{{
var initGraphics = function () {
    //init vars
    initVars();
    //Scene
    scene = new THREE.Scene();
    //add cameras
    addCameras();  
    //add lights
    addLights();

    //anim_handler
    anim_handler = THREE.AnimationHandler;

    var gameDiv = $("#gameDiv");
    gameDiv.empty();
    //Stats
    stats = new Stats();
    stats.domElement.style.position = "absolute";
    gameDiv.append(stats.domElement);

    //add status_bar
    gameDiv.append(createStatusBar());

    var size = {
        height  :SINGLE_HEIGHT,
        width   :SINGLE_WIDTH * player_num
    };   
    $("<canvas>Your Browser did not support canvas tag!</canvas>", size).appendTo(gameDiv);
    
    //Renderer
    renderer = new THREE.WebGLRenderer(new function(){
        this.canvas = $("canvas")[0];
    });
    
    renderer.setSize(size.width, size.height);

}
///}}}

//start anim
var addAnimStart = function (obj) {
    obj.start = function () {
        for (var i=0; i<this.anims.length; ++i){
            var anim = this.kf_anims[i];
            for (var h=0; h<anim.hierarchy.length; ++h){
                var keys = anim.data.hierarchy[h].keys;
                var sids = anim.data.hierarchy[h].sids;
                var root = anim.hierarchy[h];
                if (keys.length && sids){
                    for (var s=0; s<sids.length; ++s){
                        var sid = sids[s];
                        var next = anim.getNextKeyWith(sid, h, 0);
                        if (next){
                            next.apply(sid);
                        }
                    }
                    root.matrixAutoUpdate = false;
                    anim.data.hierarchy[h].node.updateMatrix();
                    obj.matrixWorldNeedsUpdate = true;
                }
            }
            anim.play(false, 0);
        }
    };
};

/* function : loadCollada
 * usage    : locadCollada(type, path, x, y, z);
 * --------------------
 * load collada model from file
 *///{{{
var loadCollada = function (type, path, x, y, z) {
    var loader = new THREE.ColladaLoader();
    loader.options.convertUpAxis = false;
    var idx = objs[type].length;
    objs[type].push(new Objs[type](0));
    var obj = objs[type][idx];
    obj.last_position = new THREE.Vector3(x,y,z);
    obj.pos = new THREE.Vector3(0,0,0);
    obj.rot = new THREE.Vector3(0,0,0);

    loader.load(path, function colladaReady(collada){
        console.log("colladaReadY");
        //dae
        var dae = collada.scene;
        var mul = 0.007;
        dae.scale.set(mul, mul, mul);
        dae.position.set(x, y, z);
        dae.updateMatrix();
        scene.add(dae);
        obj.dae = dae;
        //animations
        obj.anims = collada.animations;
        obj.progress = 0;
        obj.kf_anims = [];
        var anims = obj.anims;
        for (var i=0; i<anims.length; ++i){
            var anim = anims[i];
            anim.name += dae_loaded;
            anim_handler.add(anim);
            var kf_anim = new THREE.KeyFrameAnimation(anim.node, anim.name);
            kf_anim.time_scale = 1;
            obj.kf_anims.push(kf_anim);
        }
        //addAnimStart(obj);
        obj.start = function () {
            for (var i=0; i<this.anims.length; ++i){
                var anim = this.kf_anims[i];
                for (var h=0; h<anim.hierarchy.length; ++h){
                    var keys = anim.data.hierarchy[h].keys;
                    var sids = anim.data.hierarchy[h].sids;
                    var root = anim.hierarchy[h];
                    if (keys.length && sids){
                        for (var s=0; s<sids.length; ++s){
                            var sid = sids[s];
                            var next = anim.getNextKeyWith(sid, h, 0);
                            if (next){
                                next.apply(sid);
                            }
                        }
                        root.matrixAutoUpdate = false;
                        anim.data.hierarchy[h].node.updateMatrix();
                        obj.matrixWorldNeedsUpdate = true;
                    }
                }
                anim.play(false, 0);
            }
        };

        //load finished
        ++dae_loaded;
        if (dae_loaded % 100 === 0 || dae_loaded === dae_cnt)
            $("#processbar")[0].value = dae_loaded;
    });
    ++dae_cnt;
    return idx;
}

///}}}

/* function : animate
 * usage    : animate();
 * --------------------
 * set animation
 *///{{{
var animate = function (timestamp) {
    requestAnimationFrame(animate);
    if (dae_loaded < dae_cnt){
        return;
    }
    
    forAllMovable(function (obj){
        var frame_time = ANIM_FRAME_TIME;
        if (obj.progress >= 0 && obj.progress < ANIM_TIME){
            for (var i=0; i<obj.kf_anims.length; ++i){
                obj.kf_anims[i].update(frame_time);
            }
        }else if (obj.progress >= ANIM_TIME){
            for (var i=0; i<obj.kf_anims.length; ++i){
                obj.kf_anims[i].stop();
            }
            obj.progress = 0;
            obj.start();
        }
        obj.progress += frame_time;
        obj.last_timestamp = timestamp;
    });
    render();
    stats.update();
}
//}}}

/* function : draw
 * usage    : draw(target);
 * --------------------
 * draw all drawable things
 *///{{{
var draw = function (target) {
    render(target);
    stats.update();
}
//}}}

/* function : forAllMovable
 * usage    : forAllMovable(func);
 * --------------------
 * do func, for all movable objs
 *///{{{
var forAllMovable = function (func) {
    for (var i=0; i<10; ++i){
        for (var j=0; j<objs[i].length; ++j){
            func(objs[i][j]);
        }
    }
}
//}}}

/* function : render
 * usage    : render();
 * --------------------
 * render the scene
 *///{{{
var render = function () {
    //var timer = Date.now() * 0.0005;
    if (dae_loaded < dae_cnt){
        return;
    }
    addGravity();

    forAllMovable(function (obj) {
        obj.last_position.copy(obj.dae.position);
        obj.dae.rotation.addSelf(obj.rot);
        obj.dae.position.addSelf(obj.pos);
        if (obj.jumping > 0){
            obj.dae.position.z += JUMP_STEP + G;
            --obj.jumping;
        }
    });

    for (var i in monsters){
        var monster = monsters[i];
//        console.log(monster.countdown);
        if (monster.countdown == 0){
            monster.countdown = SHOOT_TIME + Math.floor(Math.random() * SHOOT_TIME);
            var times = SHOOT_MIN + Math.floor(Math.random() * (SHOOT_MAX - SHOOT_MIN));
            for (var j=0; j<times; ++j){
                var direction = new THREE.Vector3(Math.random(), Math.random(), Math.random());
                var pos = (new THREE.Vector3(0,0,0))
                    .add(direction.setLength(0.8), monster.dae.position);
                var idx = loadCollada(ObjType.BALL,
                        MODEL_FILES[ObjType.BALL], pos.x, pos.y, pos.z);
                balls[idx].pos = direction.setLength(0.1);
            }
        }
        --monster.countdown;
    }

    for (var i in robots){
        if (robots[i].rot.z != 0){
            var crv = cam_rel_vecs[i];
            crv.copy(rotate(crv, robots[i].rot.z));
        }
    }
    check();
    
//    camera.position.set(10, 10, 10);
    if (robots.length){
        for (var i=0; i<player_num; ++i){
            if (robots[i].dae != null){
                cameras[i].position.add(cam_rel_vecs[i], robots[i].dae.position);
                cameras[i].lookAt(robots[i].dae.position);
                cameras[i].height = cameras[i].fullHeight;
                cameras[i].width = cameras[i].fullWidth;
            }
        }
    }

    for (var i=0; i<player_num; ++i){
		var left = SINGLE_WIDTH * i;
	    var top = 0;
		var width = SINGLE_WIDTH;
		var height = SINGLE_HEIGHT;
	    renderer.setViewport(left, top, width, height);
        renderer.setScissor(left, top, width, height);
        renderer.enableScissorTest(true);
	    //renderer.setClearColor( view.background, view.background.a );
	    cameras[i].aspect = width / height;
	    cameras[i].updateProjectionMatrix();
	    renderer.render(scene, cameras[i]);
    }
}
//}}}
